<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->

<script>
  /*
   * Helper for determining when first render occurs.
   * Call `Polymer.RenderStatus.whenReady(callback)` to be notified when
   * first render occurs or immediately if it has already occured.
   * Note that since HTML Imports are designed to load before rendering,
   * this call can also be used to guarantee that imports have loaded.
   * This behavior is normalized to function correctly with the HTMLImports
   * polyfill which does not otherwise maintain this rendering guarantee.
   * Querying style and layout data before first render is currently
   * problematic on some browsers (Blink/Webkit) so this helper can be used
   * to prevent doing so until a safe time.
   */
  Polymer.RenderStatus = {

    _ready: false,

    _callbacks: [],

    whenReady: function(cb) {
      if (this._ready) {
        cb();
      } else {
        this._callbacks.push(cb);
      }
    },

    _makeReady: function() {
      this._ready = true;
      for (var i=0; i < this._callbacks.length; i++) {
        this._callbacks[i]();
      }
      this._callbacks = [];
    },

    _catchFirstRender: function() {
      requestAnimationFrame(function() {
        Polymer.RenderStatus._makeReady();
      });
    },

    _afterNextRenderQueue: [],
    _waitingNextRender: false,

    afterNextRender: function(element, fn, args) {
      this._watchNextRender();
      this._afterNextRenderQueue.push([element, fn, args]);
    },

    hasRendered: function() {
      return this._ready;
    },

    _watchNextRender: function() {
      if (!this._waitingNextRender) {
        this._waitingNextRender = true;
        var fn = function() {
          Polymer.RenderStatus._flushNextRender();
        }
        if (!this._ready) {
          this.whenReady(fn);
        } else {
          requestAnimationFrame(fn);
        }
      }
    },

    _flushNextRender: function() {
      var self = this;
      // we want to defer after render until just after the paint.
      setTimeout(function() {
        self._flushRenderCallbacks(self._afterNextRenderQueue);
        self._afterNextRenderQueue = [];
        self._waitingNextRender = false;
      });
    },

    _flushRenderCallbacks: function(callbacks) {
      for (var i=0, h; i < callbacks.length; i++) {
        h = callbacks[i];
        h[1].apply(h[0], h[2] || Polymer.nar);
      }
    }
  };

  if (window.HTMLImports) {
    HTMLImports.whenReady(function() {
      Polymer.RenderStatus._catchFirstRender();
    });
  } else {
    Polymer.RenderStatus._catchFirstRender();
  }

  // NOTE: for bc.
  Polymer.ImportStatus = Polymer.RenderStatus;
  Polymer.ImportStatus.whenLoaded = Polymer.ImportStatus.whenReady;

</script>
